#pragma once

#include <set>
#include <vector>
#include <BWAPI.h>
#include "ZerglingGroupState.h"
#include "ZerglingControllerStructs.h"

/**
 * Singleton class, accessible with getInstance();
 */
class ZerglingController
{
	public:
		void attack(std::set<BWAPI::Unit*> & units, int x, int y);
		void move(std::set<BWAPI::Unit*> & units, int x, int y);
		void free(std::set<BWAPI::Unit*> & units);
		void upkeep();
		static ZerglingController getInstance();
	private:
		ZerglingController();
		std::vector<ZerglingGroupState> fss;

		static ZerglingController INSTANCE;

		void flankGroup(std::vector<BWAPI::Unit*> & units1, std::vector<BWAPI::Unit*> & units2, int x1, int y1, int x2, int y2);
		bool detectFlank(std::set<BWAPI::Unit*> & units, int x, int y);
		std::pair<float, float> findDelta(SLine line, float distance);
		std::pair<float, float> findDeltaAway(SLine line, float distance);
		SQuadValues findQuadraticValues(SLine line, float distance);
		void formHorizLine(std::vector<BWAPI::Unit*> & units, int y, int x1, int x2, int awayX, int awayY);
		void formVertLine(std::vector<BWAPI::Unit*> & units, int x, int y1, int y2, int awayX, int awayY);
		bool formLine(std::vector<BWAPI::Unit*> & units, int x1, int y1, int x2, int y2, int awayX, int awayY);
		void prepareForLine(std::set<BWAPI::Unit*> & units, int endX, int endY, std::vector<BWAPI::Unit*> & result);
};

struct lineSortFunctor {
	bool operator()(const BWAPI::Unit * a, const BWAPI::Unit * b) {
		if (a->getHitPoints() < b->getHitPoints()) {return false;}
		else if (a->getHitPoints() > b->getHitPoints()) {return true;}
		else
		{
			BWAPI::Position aPos = a->getPosition();
			BWAPI::Position bPos = b->getPosition();
			int distA = (aPos.x() * aPos.x()) + (aPos.y() * aPos.y());
			int distB = (bPos.x() * bPos.x()) + (bPos.y() * bPos.y());
			return (distA < distB);
		}
	}
};